package com.weijianhuawen.wjblog.admin.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.weijianhuawen.wjblog.admin.convert.WikiConvert;
import com.weijianhuawen.wjblog.admin.mode.vo.wiki.*;
import com.weijianhuawen.wjblog.admin.service.AdminWikiService;
import com.weijianhuawen.wjblog.common.domain.dos.ArticleDo;
import com.weijianhuawen.wjblog.common.domain.dos.WikiCatalogDo;
import com.weijianhuawen.wjblog.common.domain.dos.WikiDo;
import com.weijianhuawen.wjblog.common.domain.mapper.ArticleMapper;
import com.weijianhuawen.wjblog.common.domain.mapper.WikiCatalogMapper;
import com.weijianhuawen.wjblog.common.domain.mapper.WikiMapper;
import com.weijianhuawen.wjblog.common.enums.ArticleTypeEnum;
import com.weijianhuawen.wjblog.common.enums.ResponseCodeEnum;
import com.weijianhuawen.wjblog.common.enums.WikiCatalogLevelEnum;
import com.weijianhuawen.wjblog.common.exception.BizException;
import com.weijianhuawen.wjblog.common.utils.PageResponse;
import com.weijianhuawen.wjblog.common.utils.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @version: java version 8
 * @Author: weijianhuawen
 * @description:
 * @date: 2024-11-11 13:46
 */
@Service
@Slf4j
public class AdminWikiServiceImpl implements AdminWikiService {
    @Resource
    private WikiMapper wikiMapper;
    @Resource
    WikiCatalogMapper wikiCatalogMapper;
    @Resource
    ArticleMapper articleMapper;
    @Override
    public Response addWiki(AddWikiReqVo vo) {
        // 将vo转换为do
        WikiDo wikiDo = WikiDo.builder()
                .cover(vo.getCover())
                .summary(vo.getSummary())
                .title(vo.getTitle())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();

        // 新增知识库
        wikiMapper.insert(wikiDo);
        // 记录插入知识库的id
        Long wikiId = wikiDo.getId();
        // 初始化默认目录
        wikiCatalogMapper.insert(WikiCatalogDo.builder().wikiId(wikiId).title("概述").sort(1).build());
        wikiCatalogMapper.insert(WikiCatalogDo.builder().wikiId(wikiId).title("基础").sort(2).build());
        return Response.success(wikiDo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response deleteWiki(DeleteWikiReqVo vo) {
        // 1 删除知识库本身 2 删除知识库所关联的文章 3 设置对应文章类型 4 删除关联的知识库目录 5 写操作同成功或失败
        // 获取需要删除知识库的id
        Long wikiId = vo.getId();
        // 删除知识库
        Integer count = wikiMapper.deleteById(wikiId);

        // 知识库不存在
        if (count == 0) {
            handlerNotExistWiki(wikiId);
        }
        // 查询所有关联的目录 并提取文章id
        List<WikiCatalogDo> wikiCatalogDos = wikiCatalogMapper.selectListByWikiId(wikiId);
        // 提取文章id
        List<Long> articleIds = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(wikiCatalogDos)) {
            articleIds = wikiCatalogDos.stream()
                    .map(WikiCatalogDo::getArticleId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
        }
        // 删除知识库所关联的所有目录
        count = wikiCatalogMapper.deleteByWikiId(wikiId);
        // 检查所关联文章id是否有其他知识库关联，如果没有，则将重置文章type
        if(!CollectionUtils.isEmpty(articleIds)) {
            // 遍历
            articleIds.forEach(articleId -> {
                // 查询
                List<WikiCatalogDo> wikiCatalogDoList = wikiCatalogMapper.selectListByArticleId(articleId);
                if (CollectionUtils.isEmpty(wikiCatalogDoList)) {
                    // 将文章类型设置为普通
                    ArticleDo articleDo = ArticleDo.builder().id(articleId).type(ArticleTypeEnum.NORMAL.getValue()).build();
                    articleMapper.updateById(articleDo);
                }
            });
        }
        return Response.success();
    }

    // 分页查询数据库
    @Override
    public PageResponse findWikiPageList(FindWikiPageListReqVo vo) {
        // 获取查询信息
        Long current = vo.getCurrent();
        Long size = vo.getSize();
        String title = vo.getTitle();
        LocalDate startDate = vo.getStartDate();
        LocalDate endDate = vo.getEndDate();

        // 执行分页查询
        Page<WikiDo> page = wikiMapper.selectPageList(current, size, title, startDate, endDate, null);
        // 获取分页数据
        List<WikiDo> wikiDos = page.getRecords();

        // 将do转换为vo
        List<FindWikiPageListRspVo> vos = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(wikiDos)) {
            vos = wikiDos.stream().map(wikiDo -> WikiConvert.INSTANCE.convertDo2Vo(wikiDo)).collect(Collectors.toList());
        }
        return PageResponse.success(page, vos);
    }

    @Override
    public Response updateWikiIsTop(UpdateWikiIsTopReqVo vo) {
        // 获取置顶状态
        Boolean isTop = vo.getIsTop();
        // 获取目标id
        Long wikiId = vo.getId();

        // 查询是否存在该知识库
        WikiDo wikiDo = wikiMapper.selectById(wikiId);

        if (Objects.isNull(wikiDo)) {
            // 知识库不存在
            handlerNotExistWiki(wikiId);
        }
        // 设置默认weight = 0
        Integer weight = 0;

        // 查询最大权重的知识库
        if (isTop) {
            wikiDo = wikiMapper.selectOneByMaxWeight();
            if (Objects.nonNull(wikiDo)) weight = wikiDo.getWeight() + 1;
        }

        // 设置最大权重
        wikiDo = WikiDo.builder()
                .id(wikiId)
                .weight(weight)
                .build();
        wikiMapper.updateById(wikiDo);
        return Response.success();
    }

    @Override
    public Response updateWikiIsPublish(UpdateWikiIsPublishReqVo vo) {
        // 获取知识库id
        Long wikiId = vo.getId();
        // 获取发布状态
        Boolean isPublish = vo.getIsPublish();

        // 查询是否存在知识库
        WikiDo wikiDo = wikiMapper.selectById(wikiId);
        if (Objects.isNull(wikiDo)) {
            handlerNotExistWiki(wikiId);
        }
        // 更新
        wikiDo = WikiDo.builder().id(wikiId).isPublish(isPublish).build();
        wikiMapper.updateById(wikiDo);
        return Response.success();
    }

    @Override
    public Response updateWiki(UpdateWikiReqVo vo) {
        // 获取相关信息
        Long wikiId = vo.getId();
        String summary = vo.getSummary();
        String cover = vo.getCover();
        String title = vo.getTitle();

        WikiDo wikiDo = wikiMapper.selectById(wikiId);
        if (Objects.isNull(wikiDo)) handlerNotExistWiki(wikiId);

        // 制作do
        wikiDo = WikiDo.builder()
                .id(wikiId)
                .title(title)
                .summary(summary)
                .cover(cover)
                .updateTime(LocalDateTime.now())
                .build();

        // 更新
        wikiMapper.updateById(wikiDo);
        return Response.success();
    }

    @Override
    public Response findOneWiki(FindOneWikiReqVo vo) {
        // 获取知识库id
        Long wikiId = vo.getId();

        WikiDo wikiDo = wikiMapper.selectById(wikiId);
        if (Objects.isNull(wikiDo)) handlerNotExistWiki(wikiId);
        // do转vo
        FindOneWikiRspVo findOneWikiRspVo = WikiConvert.INSTANCE.convertDo2OneVo(wikiDo);
        return Response.success(findOneWikiRspVo);
    }

    @Override
    public Response findWikiCatelogList(FindWikiCatalogListReqVo vo) {
        // 获取所需查询的知识库id
        Long wikiId = vo.getId();
        // 查询知识库是否存在
        WikiDo wikiDo = wikiMapper.selectById(wikiId);
        if (Objects.isNull(wikiDo)) handlerNotExistWiki(wikiId);
        // 查询所有与该id关联的目录
        List<WikiCatalogDo> wikiCatalogDoList = wikiCatalogMapper.selectListByWikiId(wikiId);
        List<FindWikiCatalogListRspVo> vos = null;
        if (!CollectionUtils.isEmpty(wikiCatalogDoList)) {
             vos = catalogCollation(null, wikiCatalogDoList, WikiCatalogLevelEnum.ONE.getValue());
        }

        return Response.success(vos);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response updateWikiCatalogs(UpdateWikiCatalogReqVo vo) {
        // 获取知识库id
        Long wikiId = vo.getId();
        // 获取更新的目录
        List<UpdateWikiCatalogItemReqVo> catalogs = vo.getCatalogs();
        // 查询知识库是否存在
        WikiDo wikiDo = wikiMapper.selectById(wikiId);
        if (Objects.isNull(wikiDo)) handlerNotExistWiki(wikiId);
        // 查询该知识库所关联的目录
        List<WikiCatalogDo> wikiCatalogDos = wikiCatalogMapper.selectListByWikiId(wikiId);

        // 删除该知识库所关联的目录
        // 获取所关联的文章
        List<Long> articleIds = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(wikiCatalogDos)) {
            articleIds = wikiCatalogDos.stream()
                    .map(WikiCatalogDo::getArticleId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
        }
        // 删除所关联的目录
        wikiCatalogMapper.deleteByWikiId(wikiId);
        // 遍历所有的文章id 如果关联表无记录 则将对应文章类型改为普通
        if(!CollectionUtils.isEmpty(articleIds)) {
            articleIds.forEach(articleId -> {
                List<WikiCatalogDo> dos = wikiCatalogMapper.selectListByArticleId(articleId);
                if (CollectionUtils.isEmpty(dos)) {
                    // 修改文章类型
                    ArticleDo articleDo = ArticleDo.builder().id(articleId).type(ArticleTypeEnum.NORMAL.getValue()).build();
                    articleMapper.updateById(articleDo);
                }
            });
        }

        // 重新插入目录数据
        if (!CollectionUtils.isEmpty(catalogs)) {
            // 重新设置sort
            resetCatalogSort(catalogs);
            // 插入目录
            insertCatalogVos(catalogs, WikiCatalogLevelEnum.ONE.getValue(), wikiId, null);
        }
        return Response.success();
    }

    // 查询文章是否存在
    private Boolean articleIsExistById(Long articleId) {
        return Objects.nonNull(articleMapper.selectByArticleId(articleId));
    }

    // 插入结构化目录
    private void insertCatalogVos(List<UpdateWikiCatalogItemReqVo> catalogs, Integer catalogLevel, Long wikiId, Long parentId) {
        if (WikiCatalogLevelEnum.ONE.getValue().equals(catalogLevel)) {
            // 插入一级目录
            // 将vo转do
            if (!CollectionUtils.isEmpty(catalogs)) {
                catalogs.forEach(catalog -> {
                    if (!StringUtils.hasLength(catalog.getTitle())) throw new BizException(ResponseCodeEnum.CATALOG_TITLE_IS_EMPTY);
                    WikiCatalogDo wikiCatalogDo = WikiCatalogDo.builder()
                            .wikiId(wikiId)
                            .title(catalog.getTitle())
                            .level(catalogLevel)
                            .sort(catalog.getSort())
                            .createTime(LocalDateTime.now())
                            .updateTime(LocalDateTime.now())
                            .build();

                    // 为被引用的文章修改类型
                    Long articleId = catalog.getArticleId();
                    if (Objects.nonNull(articleId) && articleIsExistById(articleId)){
                        wikiCatalogDo.setArticleId(articleId);
                        articleMapper.updateById(ArticleDo.builder().id(articleId).type(ArticleTypeEnum.WIKI.getValue()).build());
                    }
                    // 插入一级目录
                    wikiCatalogMapper.insert(wikiCatalogDo);
                    // 获取插入后的id，作为子节点插入的父节点id
                    Long currentId = wikiCatalogDo.getId();
                    // 为子节点添加目录
                    insertCatalogVos(catalog.getChildren(), catalogLevel + 1, wikiId, currentId);
                });
            }
        } else {
            // 插入非一级目录
            // 需要修改文章类型的文章id
            List<Long> articleIds = Lists.newArrayList();
            if (!CollectionUtils.isEmpty(catalogs)) {
                // 将vo转do
                catalogs.forEach(catalog -> {
                    if (!StringUtils.hasLength(catalog.getTitle())) throw new BizException(ResponseCodeEnum.CATALOG_TITLE_IS_EMPTY);
                    WikiCatalogDo wikiCatalogDo = WikiCatalogDo.builder()
                            .title(catalog.getTitle())
                            .level(catalogLevel)
                            .wikiId(wikiId)
                            .parentId(parentId)
                            .sort(catalog.getSort())
                            .createTime(LocalDateTime.now())
                            .updateTime(LocalDateTime.now())
                            .isDeleted(Boolean.FALSE)
                            .build();
                    Long articleId = catalog.getArticleId();
                    if (Objects.nonNull(articleId) && articleIsExistById(articleId)) {
                        wikiCatalogDo.setArticleId(articleId);
                        articleIds.add(catalog.getArticleId());
                    }
                    //插入目录
                    wikiCatalogMapper.insert(wikiCatalogDo);

                    // 新增子节点目录
                    List<UpdateWikiCatalogItemReqVo> children = catalog.getChildren();
                    if (!CollectionUtils.isEmpty(children)) insertCatalogVos(children, catalogLevel + 1, wikiId, wikiCatalogDo.getId());
                });
                // 批量修改文章状态
                articleMapper.updateArticlesByIds(ArticleDo.builder().type(ArticleTypeEnum.WIKI.getValue()).build(), articleIds);
            }
        }
    }

    // 重置各目录的sort
    private void resetCatalogSort(List<UpdateWikiCatalogItemReqVo> catalogs) {
        if (!CollectionUtils.isEmpty(catalogs)) {
            // 重置当前level目录的sort
            for (int i = 0; i < catalogs.size(); i++) {
                UpdateWikiCatalogItemReqVo vo = catalogs.get(i);
                vo.setSort(i + 1);
                // 重置子节点的sort
                List<UpdateWikiCatalogItemReqVo> child = vo.getChildren();
                if (!CollectionUtils.isEmpty(child)) resetCatalogSort(child);
            }
        }
    }

    // 判断知识库是否存在
    private void handlerNotExistWiki(Long wikiId) {
        log.warn("【知识库后台服务】 知识库不存在，id:{}", wikiId);
        throw new BizException(ResponseCodeEnum.NOT_EXIST_WIKI_ERROR);
    }

    // 格式化目录
    private List<FindWikiCatalogListRspVo> catalogCollation(List<FindWikiCatalogListRspVo> parentCatalogList, List<WikiCatalogDo> wikiCatalogDoList, Integer catalogLevel) {
        if (WikiCatalogLevelEnum.ONE.getValue().equals(catalogLevel)) {
            // 一级目录
            // 提取一级目录
            if (!CollectionUtils.isEmpty(wikiCatalogDoList)) {
                List<FindWikiCatalogListRspVo> vos = Lists.newArrayList();
                List<WikiCatalogDo> oneLevelCatalogDos = wikiCatalogDoList.stream()
                        .filter(wikiCatalogDo -> Objects.equals(wikiCatalogDo.getLevel(), catalogLevel))
                        .sorted(Comparator.comparing(WikiCatalogDo::getSort)) // 根据sort升序排列
                        .collect(Collectors.toList());

                // 将提取的一级目录do转换为vo
                for (WikiCatalogDo wikiCatalogDo : oneLevelCatalogDos) {
                    FindWikiCatalogListRspVo vo = FindWikiCatalogListRspVo.builder()
                            .id(wikiCatalogDo.getId())
                            .articleId(wikiCatalogDo.getArticleId())
                            .level(wikiCatalogDo.getLevel())
                            .sort(wikiCatalogDo.getSort())
                            .title(wikiCatalogDo.getTitle())
                            .editing(Boolean.FALSE)
                            .build();
                    vos.add(vo);
                }
                // 为一级目录添加子节点
                vos = catalogCollation(vos, wikiCatalogDoList, catalogLevel + 1);
                return vos;
            }
            return null;
        } else {
            // 其他级别目录
            // 遍历父级目录
            if (!CollectionUtils.isEmpty(parentCatalogList)) {
                parentCatalogList.forEach(parentCatalog -> {
                    // 获取父级目录id
                    Long parentId = parentCatalog.getId();
                    // 提取子集目录do
                    List<WikiCatalogDo> childCatalogDos = wikiCatalogDoList.stream()
                            .filter(wikiCatalogDo -> Objects.equals(wikiCatalogDo.getParentId(), parentId) // 满足父目录为当前所遍历的父目录
                            && Objects.equals(wikiCatalogDo.getLevel(), catalogLevel)) // 满足目标提取的目录等级
                            .sorted(Comparator.comparing(WikiCatalogDo::getSort))
                            .collect(Collectors.toList());
                    // 转换为vo
                    List<FindWikiCatalogListRspVo> childVos = null;
                    if (!CollectionUtils.isEmpty(childCatalogDos)) {
                        childVos = childCatalogDos.stream()
                                .map(wikiCatalogDo -> FindWikiCatalogListRspVo.builder()
                                        .id(wikiCatalogDo.getId())
                                        .level(wikiCatalogDo.getLevel())
                                        .sort(wikiCatalogDo.getSort())
                                        .editing(Boolean.FALSE)
                                        .title(wikiCatalogDo.getTitle())
                                        .articleId(wikiCatalogDo.getArticleId())
                                        .build())
                                .collect(Collectors.toList());
                        // 为子节点添加子节点
                        childVos = catalogCollation(childVos, wikiCatalogDoList, catalogLevel + 1);
                    }
                    // 设置父节点的child节点
                    parentCatalog.setChildren(childVos);
                });
            }
            return parentCatalogList;
        }
    }
}
